/*
 * 
 * 
 */

package DigimonAdventure.Things;

import DigimonAdventure.Database.DigimonSpecies;
import DigimonAdventure.Database.Direction;
import DigimonAdventure.Database.Speed;
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Kris Derril Siregar
 */
public abstract class AbstractDigimon extends AbstractDigimonSpecies{
    protected int level;
	protected int Life;
	//Atribut derivatif (datang dari perhitungan)
	protected int HP;
	protected int att;
	protected int def;
	protected Speed spd; //spd untuk sementara masih string, ntar gw buat enumnya
	protected int eva;
	//Atribut dasar
	protected int str;
	protected int vit;
	protected int res;
	protected int agi;
    private float hit;
    private float evd;
	public Semaphore sem;

	AbstractDigimon(int posX,int posY,DigimonSpecies species,int str,int vit,int res,int agi){
        super(posX,posY,species);
        this.vit = species.getBaseVit() + vit;
        this.str = species.getBaseStr() + str;
        this.res = species.getBaseRes() + res;
        this.agi = species.getBaseAgi() + agi;
        level = 1;
        this.HP = this.vit;
        this.att = this.str;
        this.def = this.res;
        this.eva = this.agi;
        this.spd = this.getSpd();
        this.Life = HP;
        this.sem = new Semaphore(1);

	}
    public void decLive (int damage){
        if(Life - damage < 0){
            Life = 0;
        }else{
            Life -= damage;
        }
    }
	public boolean isAlive() {
        return Life > 0;
    }
	public int getLife(){
        return Life;
    }
	public int getHP(){
        return HP;
    }
	public int getAtt(){
        return att;
    }
	public int getDef(){
        return def;
    }
	public Speed getSpd(){
        return Speed.getSpd(eva);
    }
	public int getEva(){
        return eva;
    }
	public int getStr(){
        return str;
    }
	public int getVit(){
        return vit;
    }
	public int getRes(){
        return res;
    }
	public int getAgi(){
        return agi;
    }
	public int getLvl(){
        return level;
    }
    public synchronized void addLife(int x){
        Life += x;
        if(Life > HP){
            Life = HP;
        }
    }
	public void addStr(int x){
        str += x;
    }
	public void addVit(int x){
        vit += x;
    }
	public void addRes(int x){
        res += x;
    }
	public void addAgi(int x){
        agi += x;
    }

    @Override
    public void move(Direction arah) {
        try {
            sem.acquire();
        } catch (InterruptedException ex) {}
        switch(arah){
            case ATAS :
                if(titik.y <= 1){
                    this.titik.y ++;
                }else{
                    this.titik.y --;
                }
                break;
            case BAWAH :
                if(titik.y >= 20){
                    this.titik.y --;
                }else{
                    this.titik.y ++;
                }
                break;
            case KANAN :
                if(titik.x >= 40){
                    this.titik.x --;
                }else{
                    this.titik.x ++;
                }
                break;
            case KIRI :
                if(titik.x <= 1){
                    this.titik.x ++;
                }else{
                    this.titik.x --;
                }
                break;
            default :
        }
        sem.release();
    }	
        /*
         *bagaimana dengan cara attack
         *bedakah antara digimon baik dan digimon liar???
         */
	public synchronized int attack(AbstractDigimon enemy){
       
            Random rnd = new Random();
            hit = rnd.nextFloat();
            evd = rnd.nextFloat();
            int kena = (int)(this.eva*hit*2 - enemy.eva*evd*2);
            float modifier = this.eva*hit*2/enemy.eva*evd*2;
            int damage = (int)(this.att*modifier - enemy.def/modifier);
            if (damage <= 0 && kena > 0){
                damage = 1;
            }else if (kena <= 0){
                damage = 0;
            }
            enemy.decLive(damage);
            return damage;
        
    }
    /**
     * Special move untuk tipe strength
     * Gnommon, Moriamon, Gaiamon, n Purger mode(s)
     */
    public synchronized int SpecialA(AbstractDigimon enemy){
       int damage  = (this.att*4*this.strata.getMul() - enemy.def);
       if(damage <= 1){
           damage = 1;
       }
       enemy.decLive(damage);
       this.decLive(this.getLife()/2);
       return damage;
    }
    /**
     * Special move untuk tipe vitality
     * Nymphmon, Atlanmon, Oceamon, n Linker mode(s)
     */
    public synchronized int SpecialB(AbstractDigimon enemy){
       int damage  = (this.att - enemy.def + this.getHP() + this.getDef())*this.strata.getMul();
       if(damage <= 1){
           damage = 1;
       }
       enemy.decLive(damage);
       this.decLive(this.getLife()/2);
       return damage;
    }
    /**
     * Special move untuk tipe agility
     * Fayrmon, Seyfermon, Celestiamon, n Overseer mode(s)
     */
    public synchronized int SpecialC(AbstractDigimon enemy){
       int damage  = (this.att - enemy.def)*this.getSpd().getCombo()*this.strata.getMul();
       if(damage <= 1){
           damage = 1;
       }
       enemy.decLive(damage);
       this.decLive(this.getLife()/2);
       return damage;
    }
    /**
     * Special move untuk digimon kacangan
     * Lain2, cuma biar ga ada null exception aja (klo jadi)
     */
    public synchronized int SpecialD(AbstractDigimon enemy){
       Random rnd = new Random();
            hit = rnd.nextFloat();
            evd = rnd.nextFloat();
            float modifier = this.eva*hit*2/enemy.eva*evd*2;
            int damage = (int)(this.att*modifier - enemy.def/modifier)*2;
       if(damage <= 1){
           damage = 1;
       }
       enemy.decLive(damage);
       this.decLive(this.getLife()/2);
       return damage;
    }

        /**
         * driver
         */
    public static void main(String [] args){
        
    }
}
